/*
 * Egress_Router.cc
 *
 *  Created on: May 20, 2011
 *      Author: ubuntu
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omnetpp.h>

#include <iostream>
#include <string>

#include "mpls_qos.h"
#include "MPLSPacket.h"

#include "RAR_m.h"
#include "RAA_m.h"
#include "LSP_Cost_Update_m.h"

using namespace std;

typedef struct Routing_Table
{
	int 	LSP_ID;
	int 	Link_Cost;
	char 	Next_Router[10];
	int 	InOut_Gate;


}Routing_Table;

class Ergress_Router : public cSimpleModule
{
	cOutVector 				  ErrorVector;
	double 					  Total_packets;
	double 					  Failed_packets;
	simtime_t 				  timeout;
	cMessage	     		 *Cost_timeoutEvent;
	cMessage 				 *EndOfSimulation;
	cMessage 				 *Loss_Ratio;


  protected:
	virtual void 			  initialize();
	virtual RAA              *generateNewRAA_Message(int LSP_ID, int Requested_Bandwidth, bool Reserve  );
	virtual LSP_Cost_Update  *generateNewLSPCost_Message(int LSP_ID, int cost);
	virtual void              handleMessage(cMessage *msg);

	 public:

	 Ergress_Router() 			{ Cost_timeoutEvent = NULL; }
	 virtual ~Ergress_Router()  {}

 	 Routing_Table Core_Routing_Table[10];

 	 Routing_Table & Get_Core_Routing_Table(int index) { return Core_Routing_Table[index]; };
};

Define_Module(Ergress_Router);

void Ergress_Router::initialize()
{
	ErrorVector.setName("Loss_Ratio");
	for(int i = 0; i < 10; i++)
			{
				    Get_Core_Routing_Table(i).LSP_ID = -1;
				    Get_Core_Routing_Table(i).Link_Cost = -1;
				    Get_Core_Routing_Table(i).InOut_Gate = -1;
			}

		    Get_Core_Routing_Table(0).LSP_ID         = 1;
			Get_Core_Routing_Table(0).Link_Cost      = 0;
			Get_Core_Routing_Table(0).InOut_Gate     = 0;

			Get_Core_Routing_Table(1).LSP_ID         = 2;
			Get_Core_Routing_Table(1).Link_Cost      = 0;
			Get_Core_Routing_Table(1).InOut_Gate     = 0;

			Get_Core_Routing_Table(2).LSP_ID         = 3;
			Get_Core_Routing_Table(2).Link_Cost      = 0;
			Get_Core_Routing_Table(2).InOut_Gate     = 0;

			Get_Core_Routing_Table(3).LSP_ID         = 4;
			Get_Core_Routing_Table(3).Link_Cost      = 0;
			Get_Core_Routing_Table(3).InOut_Gate     = 1;

		    Get_Core_Routing_Table(4).LSP_ID         = 5;
			Get_Core_Routing_Table(4).Link_Cost      = 0;
			Get_Core_Routing_Table(4).InOut_Gate     = 1;

			Get_Core_Routing_Table(5).LSP_ID         = 6;
			Get_Core_Routing_Table(5).Link_Cost      = 0;
			Get_Core_Routing_Table(5).InOut_Gate     = 2;

			Get_Core_Routing_Table(6).LSP_ID         = 7;
			Get_Core_Routing_Table(6).Link_Cost      = 0;
			Get_Core_Routing_Table(6).InOut_Gate     = 2;

			Get_Core_Routing_Table(7).LSP_ID         = 8;
			Get_Core_Routing_Table(7).Link_Cost      = 0;
			Get_Core_Routing_Table(7).InOut_Gate     = 3;

			Get_Core_Routing_Table(8).LSP_ID         = 9;
			Get_Core_Routing_Table(8).Link_Cost      = 0;
			Get_Core_Routing_Table(8).InOut_Gate     = 3;

			Total_packets = Failed_packets = 0;

			timeout = 1.0;
			Cost_timeoutEvent = new cMessage("Cost_timeoutEvent");
			scheduleAt(simTime()+timeout, Cost_timeoutEvent);

			Loss_Ratio = new cMessage("Loss_Ratio");
			scheduleAt(simTime()+timeout, Loss_Ratio);

			EndOfSimulation = new cMessage("EndOfSimulation");
			scheduleAt(1.0*5*60, EndOfSimulation);



}

void Ergress_Router::handleMessage(cMessage *msg)
{

	string RARClass 			("RAR");
	string MPLSClass 			("MPLSPacket");

	if (msg == EndOfSimulation)
		{
			EV << "Simulation Ended\n";
			cancelAndDelete(EndOfSimulation);
			cancelAndDelete(Cost_timeoutEvent);
			cancelAndDelete(Loss_Ratio);
			return;
		}

	else if ( msg == Loss_Ratio )
	{
		if (Total_packets)
		{
			if (Failed_packets)
			EV << "Loss Ratio: " << Failed_packets/Total_packets << "\n";
			ErrorVector.record(Failed_packets/Total_packets);
		}

		Total_packets = Failed_packets = 0;

		scheduleAt(simTime()+timeout, Loss_Ratio);
	}
	else if ( msg == Cost_timeoutEvent )
    {

#ifdef DEBUG
		EV << "Ergress Router Send <LSP_ID, Cost> Messages: \n";
#endif

		for (int i = 0; i < 9; i++)
		{
			send(generateNewLSPCost_Message(Get_Core_Routing_Table(i).LSP_ID, 0), "gate$o", Get_Core_Routing_Table(i).InOut_Gate);
		}

		scheduleAt(simTime()+timeout, Cost_timeoutEvent);
    }

	else if ( !RARClass.compare(msg->getClassName()) )
	{
		RAR *ttmsg = check_and_cast<RAR *>(msg);

#ifdef DEBUG
		EV << "RAR received at " << "Ergress Router\n" << "at gate: " <<
				ttmsg->getArrivalGate()->getIndex() << "\n" <<
				"with LSP: " << ttmsg->getLSP_ID() << "\n";
#endif

	    for ( int i = 0; i < 10; i++ )
	    {
	    	if ( ttmsg->getLSP_ID() == Get_Core_Routing_Table(i).LSP_ID )
	    	 {
	    		bool Status = (ttmsg->getRequested_Bandwidth() < (100 - Total_packets));
	    		send(generateNewRAA_Message(ttmsg->getLSP_ID(), ttmsg->getRequested_Bandwidth(), Status), "gate$o", Get_Core_Routing_Table(i).InOut_Gate); break;
	    	 }
	    }

		delete msg;
	}

	else if (uniform(0,1) < (double)par("loss_rate"))
	    {
			Failed_packets++;

#ifdef DEBUG
			EV << "ER has \"Lost\" a message " << msg << endl;
#endif

			bubble("Message lost");
	        delete msg;
	        return;
	    }

	else if ( !MPLSClass.compare(msg->getClassName()) )
	{
				Total_packets++;
#ifdef DEBUG
		MPLSPacket *ttmsg = check_and_cast<MPLSPacket *>(msg);

		EV << "MPLS received at " << getName() << "\n" << "at gate: " <<
				ttmsg->getArrivalGate()->getIndex() << "\n" <<
				"with LSP: " << ttmsg->getTopLabel() << "\n";


				EV << "MPLS Reached Ergress Router\n";
#endif

				delete msg;
	}
}

RAA *Ergress_Router::generateNewRAA_Message(int LSP_ID, int Requested_Bandwidth, bool Reserve)
{
	RAA *msg = new RAA();

	msg->setReserve(Reserve);
	msg->setLSP_ID(LSP_ID);
	msg->setRequested_Bandwidth(Requested_Bandwidth);

	return msg;
}

LSP_Cost_Update  *Ergress_Router::generateNewLSPCost_Message(int LSP_ID, int cost)
{
	LSP_Cost_Update *msg = new LSP_Cost_Update();

	msg->setLSP_ID(LSP_ID);
	msg->setCost(cost);

	return msg;
}
